import WebpackLicense from '@components/WebpackLicense';

<WebpackLicense from="https://webpack.js.org/configuration/resolve/" />

# Resolve

模块解析：该选项用于配置 Rspack 模块解析逻辑。

- **类型：** `Object`

## resolve.alias

- **类型：** `Record<string, false | string | (string | false)[]>`
- **默认值：** `{}`

路径别名，例如：

```ts
{
  "@": path.resolve(__dirname, './src'),
  "abc$": path.resolve(__dirname, './src/abc')
}
```

此时：

- `require("@/a")` 会尝试解析 `<root>/src/a`。
- `require("abc")` 会尝试解析 `<root>/src/abc`。
- `require("abc/file.js")` 不会命中匹配规则，它会尝试去解析 `node_modules/abc/files.js`。

### 对包解析的影响

当你使用 `resolve.alias` 将包名导入（例如 `import 'lib'`）重定向到 monorepo 或 `node_modules` 中的具体目录时，模块的解析方式会发生变化：

- **默认情况**：如果导入的是包名，Rspack 会执行完整的包解析流程：读取该包的 `package.json`，并根据 `[exports](https://nodejs.org/api/packages.html#exports)` 字段决定入口文件和子路径映射。
- **重定向后**：当别名被替换成实际的文件系统路径，例如 `./node_modules/lib`，Rspack 不再将其视为包名，而是按普通路径进行解析。这会跳过包的默认解析逻辑，导致 `package.json` 中的 `exports` 等字段不再生效。这是 Node.js 的标准解析行为。

### Monorepo 场景

如果希望 monorepo 中的各个包依然保持和正常 npm 包一致的解析方式，不建议通过 `alias` 将包名直接指向源码目录。
推荐的做法是使用包管理器的工作区功能，将子包符号链接到 `node_modules` 中，让它们像普通依赖一样被解析。

## resolve.aliasFields

- **类型：** `string[]`
- **默认值：**`['browser']`

定义一个字段，例如 `browser`，以依照[此规范](https://github.com/defunctzombie/package-browser-field-spec)进行解析。

## resolve.conditionNames

- **类型：** `string[]`

指定用于匹配包 [`exports` 字段](https://nodejs.org/api/packages.html#packages_exports) 入口点的 condition names（条件名称）。

```js title="rspack.config.mjs"
export default {
  resolve: {
    conditionNames: ['require', 'node'],
  },
};
```

### 默认值

Rspack 默认的 `conditionNames` 由 [mode](/config/mode)、[target](/config/target) 和模块类型共同决定。

```js
// 针对 ES modules
['import', 'module', 'webpack', mode, target];

// 针对 CommonJS
['require', 'module', 'webpack', mode, target];

// 针对 CSS 模块
['webpack', mode, 'style'];
```

在上述示例中：

- `mode` 由 [mode](/config/mode) 配置决定，开发模式下为 `development`，其他模式为 `production`。
- `target` 由 [target](/config/target) 配置决定：
  - 如果 `target` 包含 `web`，则为 `browser`。
  - 如果 `target` 包含 `node`，则为 `node`。
  - 如果 `target` 包含 `webworker`，则为 `worker`。
  - 如果 `target` 包含 `electron`，则为 `electron`。
  - 如果 `target` 包含 `nwjs`，则为 `nwjs`。

### 示例

Rspack 会匹配 `resolve.conditionNames` 数组中列出的 [export conditions](https://nodejs.org/api/packages.html#conditional-exports)。

注意，`exports` 对象中 key 的顺序决定了优先级。在条件匹配时，前面的入口优先级高于后面的入口。

例如：

```json title="package.json"
{
  "name": "foo",
  "exports": {
    ".": {
      "import": "./index-import.js",
      "require": "./index-require.js",
      "node": "./index-node.js"
    },
    "./bar": {
      "node": "./bar-node.js",
      "require": "./bar-require.js"
    },
    "./baz": {
      "import": "./baz-import.js",
      "node": "./baz-node.js"
    }
  }
}
```

```js title="rspack.config.mjs"
export default {
  resolve: {
    conditionNames: ['require', 'node'],
  },
};
```

导入时：

- `'foo'` 会被解析为 `'foo/index-require.js'`
- `'foo/bar'` 会被解析为 `'foo/bar-node.js'`，因为在条件导出对象中 `"node"` 键优先于 `"require"` 键
- `'foo/baz'` 会被解析为 `'foo/baz-node.js'`

### 扩展默认值

如果你希望在保留 Rspack 默认值的同时添加自定义的 condition names，可以使用 `"..."`：

```js title="rspack.config.mjs"
export default {
  resolve: {
    conditionNames: ['my-custom-condition', '...'],
  },
};
```

或者，如果你想让默认值优先，再追加自定义 condition names：

```js title="rspack.config.mjs"
export default {
  resolve: {
    conditionNames: ['...', 'my-custom-condition'],
  },
};
```

## resolve.descriptionFiles

- **类型：** `string[]`
- **默认值：** `['package.json']`

用于描述的 JSON 文件。

```js title="rspack.config.mjs"
export default {
  resolve: {
    descriptionFiles: ['package.json'],
  },
};
```

## resolve.enforceExtension

- **类型：** `boolean`

默认情况下，当 [resolve.extensions](#resolveextensions) 包含空字符串时，`enforceExtension` 会设置为 `true`；否则，将设置为 `false`。

如果是 `true`，将不允许无扩展名文件。默认如果 `./foo` 有 `.js` 扩展，`require('./foo')` 可以正常运行。但如果启用此选项，只有 `require('./foo.js')` 能够正常工作。

```js title="rspack.config.mjs"
export default {
  resolve: {
    enforceExtension: false,
  },
};
```

## resolve.exportsFields

- **类型：** `string[]`
- **默认值：** `["exports"]`

自定义 package.json 中的 exports 字段，例如：

```json title="lib/package.json"
{
  "name": "lib",
  "testExports": {
    ".": "./test.js"
  },
  "exports": {
    ".": "./index.js"
  }
}
```

则当配置为 `["testExports", "exports"]` 时, `import value from 'lib'` 的结果为 `lib/test.js`。

## resolve.extensions

- **类型：** `string[]`
- **默认值：** `[".js", ".json", ".wasm"]`

自动添加导入文件的扩展名。这意味着你可以导入文件，而不需要显式地写它们的扩展名。

例如，当导入 `./index` 时，Rspack 将尝试按以下顺序解析：

- `./index.js`
- `./index.json`
- `./index.wasm`

### 示例

下面演示如何配置自定义扩展名来包含 TypeScript 和 JSX 文件：

```js title="rspack.config.mjs"
export default {
  resolve: {
    extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx', '.json'],
  },
};
```

当同一目录下存在同名但扩展名不同的多个文件时，Rspack 会选择在数组中位置更靠前的扩展名对应的文件进行解析。

例如，如果同一目录下同时存在 `index.js` 和 `index.ts`，而你的配置是 `['.ts', '.js']`，那么 `import './index'` 将会解析为 `index.ts`。

### 扩展默认值

注意：显式配置 `resolve.extensions` 会完全覆盖默认数组，这意味着 Rspack 将不再尝试使用默认扩展名进行解析。

如果你希望在自定义扩展名的同时保留默认扩展名，可以使用展开语法 `'...'`：

```js title="rspack.config.mjs"
export default {
  resolve: {
    // 等价于 ['.ts', '.js', '.json', '.wasm']
    extensions: ['.ts', '...'],
  },
};
```

### 性能建议

- 避免添加过多扩展名，因为每个扩展名都会增加解析开销。尽量保持 `extensions` 数组精简以提升解析性能。
- 将最常用的扩展名放在数组前面。

## resolve.extensionAlias

- **类型：** `Record<string, string[] | string>`
- **默认值：** `{}`

定义拓展名的别名，例如：

```js title="rspack.config.mjs"
export default {
  resolve: {
    extensionAlias: {
      '.js': ['.ts', '.js'],
    },
  },
};
```

这对于 TypeScript 项目来说非常有用，因为 TypeScript 推荐使用 `.js` 扩展名来引用 TypeScript 文件。

```ts title="index.ts"
import { foo } from './foo.js'; // 实际引用的是 foo.ts
```

Rspack 在解析 `import './foo.js'` 时，会依次尝试解析 `'./foo.ts'` 和 `./foo.js`。

## resolve.fallback

- **类型：** `Record<string, false | string>`
- **默认值：** `{}`

当常规解析失败时重定向模块请求。

```js title="rspack.config.mjs"
export default {
  //...
  resolve: {
    fallback: {
      abc: false, // 不为 abc 引入 polyfill
      xyz: path.resolve(__dirname, 'path/to/file.js'), // 为 xyz 引入 polyfill
    },
  },
};
```

Rspack 默认不会为 Node.js 核心模块提供 polyfills，这意味着如果你在浏览器或类似环境中运行的代码中使用它们，你将需要从 NPM 安装兼容的模块并自行包含它们。

你可以使用 [node-polyfill-webpack-plugin](https://www.npmjs.com/package/node-polyfill-webpack-plugin) 来自动 polyfill Node.js 核心模块。

```js title="rspack.config.mjs"
import NodePolyfillPlugin from 'node-polyfill-webpack-plugin';

export default {
  // ...
  plugins: [new NodePolyfillPlugin()],
};
```

或者参考 webpack 4 使用的 Node.js polyfills 列表：

```js title="rspack.config.mjs"
import { createRequire } from 'node:module';

const require = createRequire(import.meta.url);

export default {
  //...
  resolve: {
    fallback: {
      assert: require.resolve('assert'),
      buffer: require.resolve('buffer'),
      console: require.resolve('console-browserify'),
      constants: require.resolve('constants-browserify'),
      crypto: require.resolve('crypto-browserify'),
      domain: require.resolve('domain-browser'),
      events: require.resolve('events'),
      http: require.resolve('stream-http'),
      https: require.resolve('https-browserify'),
      os: require.resolve('os-browserify/browser'),
      path: require.resolve('path-browserify'),
      punycode: require.resolve('punycode'),
      process: require.resolve('process/browser'),
      querystring: require.resolve('querystring-es3'),
      stream: require.resolve('stream-browserify'),
      string_decoder: require.resolve('string_decoder'),
      sys: require.resolve('util'),
      timers: require.resolve('timers-browserify'),
      tty: require.resolve('tty-browserify'),
      url: require.resolve('url'),
      util: require.resolve('util'),
      vm: require.resolve('vm-browserify'),
      zlib: require.resolve('browserify-zlib'),
    },
  },
};
```

## resolve.importsFields

- **类型：** `string[]`
- **默认值:** `['imports']`

自定义 package.json 中的 imports 字段，用于提供包的内部请求（以 `#` 开头的请求被视为内部请求）

例如：

```json title="package.json"
{
  "name": "lib",
  "imports": {
    "#foo": "./src/foo.js",
    "#common/*": "./src/common/*.js"
  },
  "testImports": {
    "#foo": "./src/test/foo.js"
  }
}
```

则当配置为 ["testImports", "imports"] 时, 当前包内 `import value from '#foo'` 的结果为 `src/test/foo.js`。

## resolve.mainFields

- **类型：** `string[]`
- **默认值：** 根据 [target](/config/target) 选项确定

控制用于定位包入口文件的 package.json 字段优先级。Rspack 在解析 npm 包入口时，会按该列表的顺序依次尝试这些字段。

当 `target` 配置为 `'web'`, `'webworker'`, 或未指定时，默认值为 `["browser", "module", "main"]`。

```js title="rspack.config.mjs"
export default {
  resolve: {
    mainFields: ['browser', 'module', 'main'],
  },
};
```

对于任何其他 `target`（包括 `'node'`）, 默认值为 `["module", "main"]`。

```js title="rspack.config.mjs"
export default {
  resolve: {
    mainFields: ['module', 'main'],
  },
};
```

例如，对于一个名为 `foo` 的库，它的 `package.json` 包含以下字段：

```json title="package.json"
{
  "name": "foo",
  "browser": "./dist/browser.js",
  "module": "./dist/module.js"
}
```

当 `import foo from 'foo'` 时，Rspack 会解析到 `browser` 字段中的模块，因为 `browser` 字段在 `mainFields` 数组中优先级最高。

注意 [`exports` 字段](https://nodejs.org/api/packages.html#packages_exports) 的优先级高于 `mainFields`。如果入口通过 `exports` 解析成功，Rspack 会忽略 `browser`、`module` 和 `main` 字段。

例如，下面的 package.json 中，`lib` 会通过 `exports` 字段解析到 `./dist/index.mjs`，而 `main` 字段将被忽略。

```json title="package.json"
{
  "name": "lib",
  "main": "./dist/index.cjs",
  "exports": {
    ".": "./dist/index.mjs"
  }
}
```

## resolve.mainFiles

- **类型：** `string[]`
- **默认值：** `["index"]`

解析目录时的文件名后缀，例如 `require('./dir/')` 会尝试解析 `'./dir/index'`。

可以配置多个文件名后缀：

```js title="rspack.config.mjs"
export default {
  resolve: {
    mainFiles: ['index', 'main'],
  },
};
```

## resolve.modules

- **类型：** `string[]`
- **默认值：** `["node_modules"]`

解析依赖时的目录名。

## resolve.preferRelative

- **类型：** `boolean`
- **默认值：** `false`

当开启时，`require('file')` 会首先寻找当前目录下的 `./file` 文件，而不是 `<modules>/file`。

## resolve.preferAbsolute

- **类型：** `boolean`
- **默认值：**`false`

在解析时，倾向使用与 `resolve.roots` 相关的绝对路径。

## resolve.tsConfig

Rspack 中用来替代 [tsconfig-paths-webpack-plugin](https://www.npmjs.com/package/tsconfig-paths-webpack-plugin) 的配置。

- **类型：** `string | object | undefined`
- **默认值:** `undefined`

```js title="rspack.config.mjs"
export default {
  resolve: {
    // string
    tsConfig: path.resolve(__dirname, './tsconfig.json'),
    // or object
    tsconfig: {
      configFile: path.resolve(__dirname, './tsconfig.json'),
      references: 'auto',
    },
  },
};
```

[点击查看例子](https://github.com/rspack-contrib/rstack-examples/tree/main/rspack/basic-ts)。

### resolve.tsConfig.configFile

- **类型：** `string`

这个选项接受的是 `tsconfig.json` 的文件路径。在开启这个选项后， Rspack 会基于 `tsconfig.json` 中 的 `paths` 和 `baseUrl` 来寻找模块，其功能等同于 [tsconfig-paths-webpack-plugin](https://www.npmjs.com/package/tsconfig-paths-webpack-plugin)。

### resolve.tsConfig.references

- **类型：** `string[] | "auto" | undefined`
- **默认值:** `undefined`

支持 [tsconfig-paths-webpack-plugin](https://github.com/dividab/tsconfig-paths-webpack-plugin#references-_string-defaultundefined) 中定义的 [tsconfig project references](https://www.typescriptlang.org/docs/handbook/project-references.html).

可以通过文件路径用于手动配置，或者使用 `auto` 用于自动读取 `tsconfig.references` 中的文件路径。

使用 `undefined` 将会关闭该功能。

## resolve.fullySpecified

- **类型：** `boolean`
- **默认值：** `false`

不再解析扩展名，不再解析 package.json 中的 mainFiles（但不会影响来自 mainFiles, browser, alias 的请求）。

## resolve.restrictions

- **类型：** `string[]`
- **默认值：**`[]`

限制请求解析路径的解析限制列表。

## resolve.roots

- **类型：** `string[]`
- **默认值：**`[]`

一个目录列表，用于解析服务器相对 URL（以'/'开头的 URL）。默认使用 context 配置选项。在非 Windows 系统上，这些请求首先作为绝对路径进行解析。

## resolve.symlinks

- **类型：** `boolean`
- **默认值：**`true`

是否将符号链接（symlink）解析到它们的符号链接位置（symlink location）。

启用时，符号链接的资源，将解析为其**真实**路径，而不是其符号链接的位置。注意，当使用创建符号链接包的工具（如 `npm link`）时，这种方式可能会导致模块解析失败。

## resolve.byDependency

- **类型：** `Record<string, Resolve>`.

依据模块类型自定义 Resolve 配置。

## resolve.pnp

- **类型:** `boolean`
- **默认值:** `!!process.versions.pnp`

启用时，将使用 [Yarn PnP](https://yarnpkg.com/features/pnp) 算法进行路径解析。

当 [`!!process.versions.pnp`](https://yarnpkg.com/advanced/pnpapi#processversionspnp) 为 `true` 时（即应用在 Yarn PnP 环境中运行时），它默认是启用的。

```js title="rspack.config.mjs"
export default {
  // ...
  resolve: {
    pnp: true,
  },
};
```
